﻿using Microsoft.Phone.Controls;
using Microsoft.Phone.Maps.Controls;
using Microsoft.Phone.Shell;
using NExtra.Geo;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Device.Location;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;

namespace runtohealth
{
    /////////////////////////////////////////////// Main Class ///////////////////////////////////////////////////////////
    #region Main Class
    public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
    {
        private GeoCoordinateWatcher _watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
        private MapPolyline _line;
        private DispatcherTimer _timer = new DispatcherTimer();
        private long _startTime;
        private string postface;
        public event PropertyChangedEventHandler PropertyChanged;
        private double _kilometres;
        private long _previousPositionChangeTick;
        private ToDoDataContext toDoDB;
        private ObservableCollection<ToDoItem> _toDoItems;

        #region MainPage
        public MainPage()
        {
            InitializeComponent();

            toDoDB = new ToDoDataContext(ToDoDataContext.DBConnectionString);

            this.DataContext = this;

            _line = new MapPolyline();
            _line.StrokeColor = Colors.Red;
            _line.StrokeThickness = 5;
            Map.MapElements.Add(_line);
            _watcher.PositionChanged += Watcher_PositionChanged;
            _timer.Interval = TimeSpan.FromSeconds(1);
            _timer.Tick += Timer_Tick;
        }
        #endregion

        #region OnNavigatedFrom
        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            // Call the base method.
            base.OnNavigatedFrom(e);
            // Save changes to the database.
            toDoDB.SubmitChanges();
        }
        #endregion

        #region OnNavigateTO
        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            // Define the query to gather all of the to-do items.
            var toDoItemsInDB = from ToDoItem todo in toDoDB.ToDoItems select todo;
            // Execute the query and place the results into a collection.
            ToDoItems = new ObservableCollection<ToDoItem>(toDoItemsInDB);
            // Call the base method.
            base.OnNavigatedTo(e);
        }
        #endregion

        #region Timer
        private void Timer_Tick(object sender, EventArgs e)
        {
            TimeSpan runTime = TimeSpan.FromMilliseconds(System.Environment.TickCount - _startTime);
            timeLabel.Text = runTime.ToString(@"hh\:mm\:ss");
        }
        #endregion

        #region MapPosition
        private void Watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e)
        {
            var coord = new GeoCoordinate(e.Position.Location.Latitude, e.Position.Location.Longitude);

            if (_line.Path.Count > 0)
            {
                var previousPoint = _line.Path.Last();
                var distance = coord.GetDistanceTo(previousPoint);
                var millisPerKilometer = (1000.0 / distance) * (System.Environment.TickCount - _previousPositionChangeTick);
                _kilometres += distance / 1000.0;

                paceLabel.Text = TimeSpan.FromMilliseconds(millisPerKilometer).ToString(@"mm\:ss");
                distanceLabel.Text = string.Format("{0:f2} km", _kilometres);
                caloriesLabel.Text = string.Format("{0:f0}", _kilometres * 65);

                PositionHandler handler = new PositionHandler();
                var heading = handler.CalculateBearing(new Position(previousPoint), new Position(coord));
                Map.SetView(coord, Map.ZoomLevel, heading, MapAnimationKind.Parabolic);

                ShellTile.ActiveTiles.First().Update(new IconicTileData()
                {
                    Title = "Run to Health",
                    WideContent1 = string.Format("{0:f2} km", _kilometres),
                    WideContent2 = string.Format("{0:f0} calories", _kilometres * 65),
                });
            }
            else
            {
                Map.Center = coord;
            }

            _line.Path.Add(coord);
            _previousPositionChangeTick = System.Environment.TickCount;
        }
        #endregion

        #region ToDoItem
        public ObservableCollection<ToDoItem> ToDoItems
        {
            get
            {
                return _toDoItems;
            }
            set
            {
                if (_toDoItems != value)
                {
                    _toDoItems = value;
                    NotifyPropertyChanged("ToDoItems");
                }
            }
        }
        #endregion

        #region NotifyPropertyChanged
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        #region Post Publish Facebook
        private async void PublishStory()
        {
            await this.loginButton.RequestNewPermissions("publish_stream");

            var facebookClient = new Facebook.FacebookClient(this.loginButton.CurrentSession.AccessToken);
            
            //link = "http://www.google.com",
            var postParams = new
            {
                name = "I'm run from Run to health ",
                caption = " Windows Phone Application  " + DateTime.Now.ToString(),
                description = postface,
                picture = "http://www.clker.com/cliparts/e/w/T/q/9/L/running-icon-on-transparent-background-md.png"
            };

            try
            {
                dynamic fbPostTaskResult = await facebookClient.PostTaskAsync("/me/feed", postParams);
                var result = (IDictionary<string, object>)fbPostTaskResult;

                Dispatcher.BeginInvoke(() =>
                {
                    MessageBox.Show("Post success !!!", "Result", MessageBoxButton.OK);
                });
            }
            catch (Exception ex)
            {
                Dispatcher.BeginInvoke(() =>
                {
                    MessageBox.Show("Exception during post: " + ex.Message, "Error", MessageBoxButton.OK);
                });
            }
        }
        #endregion

        #region Start Button
        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            if (_timer.IsEnabled)
            {
                _watcher.Stop();
                _timer.Stop();
                StartButton.Content = "Start";
                // Create a new to-do item based on the text box.
                ToDoItem newToDo = new ToDoItem
                {
                    ItemName = "Distance : " + distanceLabel.Text +
                               "  Calories : " + caloriesLabel.Text,
                    IsComplete = " Duration : " + timeLabel.Text
                };
                // Add a to-do item to the observable collection.
                ToDoItems.Add(newToDo);
                // Add a to-do item to the local database.
                toDoDB.ToDoItems.InsertOnSubmit(newToDo);

                _kilometres = 0;
                paceLabel.Text = TimeSpan.FromMilliseconds(0).ToString(@"mm\:ss");
            }
            else
            {
                _watcher.Start();
                _timer.Start();
                _startTime = System.Environment.TickCount;
                StartButton.Content = "Stop";
            }
        }
        #endregion
        
        #region Deleate Button
        private void deleteTaskButton_Click(object sender, RoutedEventArgs e)
        {
            // Cast parameter as a button.
            var button = sender as Button;

            if (button != null)
            {
                // Get a handle for the to-do item bound to the button.
                ToDoItem toDoForDelete = button.DataContext as ToDoItem;
                // Remove the to-do item from the observable collection.
                ToDoItems.Remove(toDoForDelete);
                // Remove the to-do item from the local database.
                toDoDB.ToDoItems.DeleteOnSubmit(toDoForDelete);
                // Save changes to the database.
                toDoDB.SubmitChanges();
                // Put the focus back to the main page.
                this.Focus();
            }
        }
        #endregion

        #region Share Button
        private void shareTaskButton_Click(object sender, RoutedEventArgs e)
        {
            var button = sender as Button;

            if (button != null)
            {
                ToDoItem toDoForPost = button.DataContext as ToDoItem;
                
                 postface =   toDoForPost.IsComplete.ToString() + " " + toDoForPost.ItemName.ToString() + " cal";

                this.Focus();
                this.PublishStory();
            }
        }
        #endregion

    }
    #endregion
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    /////////////////////////////////////////////// Create DataBase Class ////////////////////////////////////////////////
    #region ToDoItem Class
    [Table]
    public class ToDoItem : INotifyPropertyChanged, INotifyPropertyChanging
    {
        #region Data Column
        // Define ID: private field, public property and database column.
        private int _toDoItemId;

        [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", 
                CanBeNull = false, AutoSync = AutoSync.OnInsert)]
        public int ToDoItemId
        {
            get
            {
                return _toDoItemId;
            }
            set
            {
                if (_toDoItemId != value)
                {
                    NotifyPropertyChanging("ToDoItemId");
                    _toDoItemId = value;
                    NotifyPropertyChanged("ToDoItemId");
                }
            }
        }

        // Define item name: private field, public property and database column.
        private string _itemName;

        [Column]
        public string ItemName
        {
            get
            {
                return _itemName;
            }
            set
            {
                if (_itemName != value)
                {
                    NotifyPropertyChanging("ItemName");
                    _itemName = value;
                    NotifyPropertyChanged("ItemName");
                }
            }
        }

        // Define completion value: private field, public property and database column.
        private string _isComplete;

        [Column]
        public string IsComplete
        {
            get
            {
                return _isComplete;
            }
            set
            {
                if (_isComplete != value)
                {
                    NotifyPropertyChanging("IsComplete");
                    _isComplete = value;
                    NotifyPropertyChanged("IsComplete");
                }
            }
        }
        // Version column aids update performance.
        [Column(IsVersion = true)]
        private Binary _version;
        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify the page that a data context property changed
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region INotifyPropertyChanging Members

        public event PropertyChangingEventHandler PropertyChanging;

        // Used to notify the data context that a data context property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }
    #endregion
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    ////////////////////////////////////////////// Connect DataBase Class ////////////////////////////////////////////////
    #region ToDoDataContext Class
    public class ToDoDataContext : DataContext
    {
        // Specify the connection string as a static, used in main page and app.xaml.
        public static string DBConnectionString = "Data Source=isostore:/ToDo.sdf";

        // Pass the connection string to the base class.
        public ToDoDataContext(string connectionString)
            : base(connectionString)
        { }

        // Specify a single table for the to-do items.
        public Table<ToDoItem> ToDoItems;
    }
#endregion
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}